package cn.zhxu.toys.captcha.impl;

import cn.zhxu.toys.captcha.*;
import org.springframework.beans.factory.InitializingBean;

/**
 * @author Troy.Zhou @ 2022/8/16 11:55
 */
public class BaseCaptchaManager implements CaptchaManager, InitializingBean {

    public static final String ATTR_EXPIRE_SECONDS = "expireSeconds";

    /** 验证码生成器 */
    private CodeGenerator codeGenerator;

    /** 验证码渲染器 */
    private CodeRenderer codeRenderer;

    /** 验证码持久化服务 */
    private CaptchaStorage captchaStorage;

    /** 验证码有效时间 */
    private int expireSeconds = 5 * 60;

    /** 最大允许验证次数 */
    private int maxAllowedTrys = 3;

    @Override
    public void genAndRender(String captchaId, CaptchaAttrs attrs) throws CaptchaException {
        CodeGenerator.CodeResult result = codeGenerator.generate();
        codeRenderer.render(result.getCode(), attrs);
        Integer expireSeconds = attrs.get(ATTR_EXPIRE_SECONDS, Integer.class, this.expireSeconds);
        captchaStorage.save(captchaId, result.getCheck(), expireSeconds);
    }

    @Override
    public VerifyResult verify(String captchaId, String code) {
        if (code == null) {
            return VerifyResult.INVALID;
        }
        Captcha captcha = captchaStorage.findCaptcha(captchaId);
        if (captcha == null) {
            return VerifyResult.INVALID;
        }
        if (captcha.isExpired()) {
            return VerifyResult.EXPIRED;
        }
        if (code.equals(captcha.getCode())) {
            // 验证成功，删除验证码
            captchaStorage.delete(captchaId);
            return VerifyResult.SUCCESS;
        }
        int trys = captcha.increaseTrys();
        if (trys >= maxAllowedTrys) {
            // 已达到最大尝试次数，删除验证码
            captchaStorage.delete(captchaId);
        } else {
            // 重新保存验证码
            captchaStorage.save(captchaId, captcha);
        }
        return VerifyResult.INVALID;
    }

    @Override
    public void afterPropertiesSet() {
        if (captchaStorage == null) {
            throw new IllegalStateException("You must set a CaptchaStorage into CaptchaManager");
        }
        if (codeRenderer == null) {
            throw new IllegalStateException("You must set a CodeRenderer into CaptchaManager");
        }
        if (codeGenerator == null) {
            codeGenerator = new RandomCharCodeGenerator();
        }
    }

    public CodeGenerator getCodeGenerator() {
        return codeGenerator;
    }

    public void setCodeGenerator(CodeGenerator codeGenerator) {
        this.codeGenerator = codeGenerator;
    }

    public CodeRenderer getCodeRenderer() {
        return codeRenderer;
    }

    public void setCodeRenderer(CodeRenderer codeRenderer) {
        this.codeRenderer = codeRenderer;
    }

    public CaptchaStorage getCaptchaStorage() {
        return captchaStorage;
    }

    public void setCaptchaStorage(CaptchaStorage captchaStorage) {
        this.captchaStorage = captchaStorage;
    }

    public int getExpireSeconds() {
        return expireSeconds;
    }

    public void setExpireSeconds(int expireSeconds) {
        this.expireSeconds = expireSeconds;
    }

    public int getMaxAllowedTrys() {
        return maxAllowedTrys;
    }

    public void setMaxAllowedTrys(int maxAllowedTrys) {
        this.maxAllowedTrys = maxAllowedTrys;
    }

}
